summaryrefslogtreecommitdiff
path: root/app/[lng]/test
diff options
context:
space:
mode:
Diffstat (limited to 'app/[lng]/test')
-rw-r--r--app/[lng]/test/agentforce-poc-faq/page.tsx62
-rw-r--r--app/[lng]/test/agentforce-poc-summary/page.tsx291
2 files changed, 353 insertions, 0 deletions
diff --git a/app/[lng]/test/agentforce-poc-faq/page.tsx b/app/[lng]/test/agentforce-poc-faq/page.tsx
new file mode 100644
index 00000000..493828d6
--- /dev/null
+++ b/app/[lng]/test/agentforce-poc-faq/page.tsx
@@ -0,0 +1,62 @@
+'use client'
+
+import { useState, useRef } from 'react'
+
+export default function AgentforcePocPage() {
+ const [isLoading, setIsLoading] = useState(true)
+ const iframeRef = useRef<HTMLIFrameElement>(null)
+
+ const handleIframeLoad = () => {
+ setIsLoading(false)
+ }
+
+ const refreshIframe = () => {
+ if (iframeRef.current) {
+ setIsLoading(true)
+ iframeRef.current.src = iframeRef.current.src
+ }
+ }
+
+ return (
+ <div className="min-h-screen bg-gray-50 p-4">
+ <div className="max-w-7xl mx-auto">
+ <div className="mb-6 flex items-center justify-between">
+ <h1 className="text-3xl font-bold text-gray-900">
+ Agentforce POC
+ </h1>
+ <button
+ onClick={refreshIframe}
+ className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
+ >
+ 새로고침
+ </button>
+ </div>
+
+ <div className="bg-white rounded-lg shadow-lg overflow-hidden">
+ {isLoading && (
+ <div className="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center z-10">
+ <div className="text-center">
+ <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"></div>
+ <p className="text-gray-600">로딩 중...</p>
+ </div>
+ </div>
+ )}
+
+ <div className="relative" style={{ height: '800px' }}>
+ <iframe
+ ref={iframeRef}
+ src="/agentforce-poc.html"
+ title="Agentforce POC"
+ className="w-full h-full border-0"
+ onLoad={handleIframeLoad}
+ />
+ </div>
+ </div>
+
+ <div className="mt-4 text-sm text-gray-500 text-center">
+ 이 페이지는 Salesforce Agentforce POC를 iframe으로 표시합니다.
+ </div>
+ </div>
+ </div>
+ )
+} \ No newline at end of file
diff --git a/app/[lng]/test/agentforce-poc-summary/page.tsx b/app/[lng]/test/agentforce-poc-summary/page.tsx
new file mode 100644
index 00000000..fc504cd3
--- /dev/null
+++ b/app/[lng]/test/agentforce-poc-summary/page.tsx
@@ -0,0 +1,291 @@
+"use client";
+
+import * as React from "react";
+import { useState } from "react";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Textarea } from "@/components/ui/textarea";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Badge } from "@/components/ui/badge";
+import { Plus, Trash2, Send, Loader2 } from "lucide-react";
+import { toast } from "sonner";
+
+interface ChatMessage {
+ id: string;
+ sender: "SHI" | "Partner";
+ message: string;
+}
+
+interface SummaryResponse {
+ issue: string;
+ request: string;
+ summary: string;
+}
+
+export default function AgentForcePOCSummaryPage() {
+ const [messages, setMessages] = useState<ChatMessage[]>([
+ {
+ id: "1",
+ sender: "SHI",
+ message: "최근 입고된 발전기 제어반 견적서에서 납기 조건 누락을 확인했습니다. 계약 전 꼭 납기 포함한 수정본 제출 부탁드립니다."
+ },
+ {
+ id: "2",
+ sender: "Partner",
+ message: "네, 누락 사항 확인 후 납기 조건 명시하여 오늘 중으로 재제출 하겠습니다."
+ },
+ {
+ id: "3",
+ sender: "SHI",
+ message: "감사합니다. 납기 조건은 계약 핵심 조항입니다. 반드시 반영해 주세요."
+ }
+ ]);
+
+ const [summaryResult, setSummaryResult] = useState<SummaryResponse | null>(null);
+ const [isLoading, setIsLoading] = useState(false);
+
+ // 새 메시지 추가
+ const addMessage = () => {
+ const newMessage: ChatMessage = {
+ id: Date.now().toString(),
+ sender: "SHI",
+ message: ""
+ };
+ setMessages([...messages, newMessage]);
+ };
+
+ // 메시지 삭제
+ const removeMessage = (id: string) => {
+ if (messages.length > 1) {
+ setMessages(messages.filter(msg => msg.id !== id));
+ } else {
+ toast.error("최소 1개의 메시지는 유지해야 합니다.");
+ }
+ };
+
+ // 메시지 업데이트
+ const updateMessage = (id: string, field: keyof ChatMessage, value: string) => {
+ setMessages(messages.map(msg =>
+ msg.id === id ? { ...msg, [field]: value } : msg
+ ));
+ };
+
+ // 요약 API 호출
+ const handleSummarize = async () => {
+ // 유효성 검사
+ const emptyMessages = messages.filter(msg => !msg.message.trim());
+ if (emptyMessages.length > 0) {
+ toast.error("모든 메시지를 입력해주세요.");
+ return;
+ }
+
+ setIsLoading(true);
+ try {
+ // 토큰 가져오기
+ const tokenResponse = await fetch('https://pyheroku-d21d18e4f257.herokuapp.com/api/getToken', {
+ method: 'POST'
+ });
+
+ if (!tokenResponse.ok) {
+ throw new Error('토큰을 가져오는데 실패했습니다.');
+ }
+
+ const tokenData = await tokenResponse.json();
+ const accessToken = tokenData.access_token;
+
+ if (!accessToken) {
+ throw new Error('토큰이 없습니다.');
+ }
+
+ // 요약 API 호출
+ const summaryResponse = await fetch(`https://connect-flow-8014--ps.sandbox.my.salesforce.com/services/apexrest/summarizeChat/`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${accessToken}`,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ chatlog: JSON.stringify(messages.map(msg => ({
+ sender: msg.sender,
+ message: msg.message
+ })))
+ })
+ });
+
+ if (!summaryResponse.ok) {
+ throw new Error(`API 호출 실패: ${summaryResponse.status}`);
+ }
+
+ const result = await summaryResponse.json();
+ setSummaryResult(result);
+ toast.success("요약이 완료되었습니다.");
+ } catch (error) {
+ console.error('요약 API 호출 실패:', error);
+ toast.error(`요약 중 오류가 발생했습니다: ${error instanceof Error ? error.message : '알 수 없는 오류'}`);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+ <div className="container mx-auto py-8 space-y-6">
+ <div className="text-center space-y-2">
+ <h1 className="text-3xl font-bold">AgentForce POC 요약 테스트</h1>
+ <p className="text-muted-foreground">
+ 대화 기록을 입력하고 AI 요약 기능을 테스트해보세요
+ </p>
+ </div>
+
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
+ {/* 입력 섹션 */}
+ <Card>
+ <CardHeader>
+ <CardTitle className="flex items-center justify-between">
+ 대화 기록 입력
+ <Button onClick={addMessage} size="sm" variant="outline">
+ <Plus className="h-4 w-4 mr-2" />
+ 메시지 추가
+ </Button>
+ </CardTitle>
+ </CardHeader>
+ <CardContent className="space-y-4">
+ {messages.map((message, index) => (
+ <div key={message.id} className="space-y-2 p-4 border rounded-lg">
+ <div className="flex items-center justify-between">
+ <div className="flex items-center gap-2">
+ <Badge variant={message.sender === "SHI" ? "default" : "secondary"}>
+ {message.sender}
+ </Badge>
+ <span className="text-sm text-muted-foreground">메시지 {index + 1}</span>
+ </div>
+ <Button
+ onClick={() => removeMessage(message.id)}
+ size="sm"
+ variant="ghost"
+ className="text-red-500 hover:text-red-700"
+ >
+ <Trash2 className="h-4 w-4" />
+ </Button>
+ </div>
+
+ <div className="space-y-2">
+ <div className="flex gap-2">
+ <Button
+ size="sm"
+ variant={message.sender === "SHI" ? "default" : "outline"}
+ onClick={() => updateMessage(message.id, "sender", "SHI")}
+ >
+ SHI
+ </Button>
+ <Button
+ size="sm"
+ variant={message.sender === "Partner" ? "default" : "outline"}
+ onClick={() => updateMessage(message.id, "sender", "Partner")}
+ >
+ Partner
+ </Button>
+ </div>
+
+ <Textarea
+ value={message.message}
+ onChange={(e) => updateMessage(message.id, "message", e.target.value)}
+ placeholder="메시지를 입력하세요..."
+ className="min-h-20"
+ />
+ </div>
+ </div>
+ ))}
+
+ <Button
+ onClick={handleSummarize}
+ disabled={isLoading}
+ className="w-full"
+ >
+ {isLoading ? (
+ <>
+ <Loader2 className="h-4 w-4 mr-2 animate-spin" />
+ 요약 중...
+ </>
+ ) : (
+ <>
+ <Send className="h-4 w-4 mr-2" />
+ 요약하기
+ </>
+ )}
+ </Button>
+ </CardContent>
+ </Card>
+
+ {/* 결과 섹션 */}
+ <Card>
+ <CardHeader>
+ <CardTitle>요약 결과</CardTitle>
+ </CardHeader>
+ <CardContent className="space-y-4">
+ {summaryResult ? (
+ <div className="space-y-4">
+ <div className="space-y-2">
+ <h4 className="font-semibold text-sm text-muted-foreground">이슈</h4>
+ <div className="p-3 bg-muted rounded-md">
+ {summaryResult.issue}
+ </div>
+ </div>
+
+ <div className="space-y-2">
+ <h4 className="font-semibold text-sm text-muted-foreground">요청</h4>
+ <div className="p-3 bg-muted rounded-md">
+ {summaryResult.request}
+ </div>
+ </div>
+
+ <div className="space-y-2">
+ <h4 className="font-semibold text-sm text-muted-foreground">요약 메시지</h4>
+ <div className="p-3 bg-muted rounded-md">
+ {summaryResult.summary}
+ </div>
+ </div>
+ </div>
+ ) : (
+ <div className="text-center py-8 text-muted-foreground">
+ <Send className="h-12 w-12 mx-auto mb-4 opacity-50" />
+ <p>요약하기 버튼을 클릭하여 결과를 확인하세요</p>
+ </div>
+ )}
+ </CardContent>
+ </Card>
+ </div>
+
+ {/* 미리보기 섹션 */}
+ <Card>
+ <CardHeader>
+ <CardTitle>API 요청 미리보기</CardTitle>
+ </CardHeader>
+ <CardContent>
+ <div className="space-y-4">
+ <div>
+ <h4 className="font-semibold text-sm text-muted-foreground mb-2">Request Body</h4>
+ <pre className="bg-muted p-4 rounded-md text-sm overflow-x-auto">
+ {JSON.stringify({
+ conversation: JSON.stringify(messages.map(msg => ({
+ sender: msg.sender,
+ message: msg.message
+ })))
+ }, null, 2)}
+ </pre>
+ </div>
+
+ {/* <div>
+ <h4 className="font-semibold text-sm text-muted-foreground mb-2">Headers</h4>
+ <pre className="bg-muted p-4 rounded-md text-sm overflow-x-auto">
+ {JSON.stringify({
+ 'Authorization': 'Bearer {access_token}',
+ 'Content-Type': 'application/json'
+ }, null, 2)}
+ </pre>
+ </div> */}
+ </div>
+ </CardContent>
+ </Card>
+ </div>
+ );
+}